<?php

namespace redis;

use Predis\Client;
use think\Config;
use think\Log;

/**
 * predis单例模式
 * @author fzf
 *
 */
class Predis
{
    private static $reids;
    private static $options = [
        'host' => 'localhost',
        'password' => null,
        'port' => 6379,
        'database' => 0,
        'read_write_timeout' => 0
    ];

    private function __construct()
    {
    }

    private function __clone()
    {
    }

    static function __callstatic($name, $args)
    {
        self::init();
        return call_user_func_array([self::$reids, $name], $args);
    }

    protected static function init()
    {
        if (empty(self::$reids)) {
            $config = Config::get('redis');
            $default = $config['default'];
            $default = array_merge(self::$options, $default);

            self::$reids = new Client($default);
        }

        return self::$reids;
    }

    /**
     * 消息订阅
     * @param string|array $channel 频道
     * @param function $callback 回调
     */
    static function subscribe($channel, $callback)
    {
        self::init();
        $pubsub = self::$reids->pubSubLoop();
        $pubsub->subscribe($channel);
        foreach ($pubsub as $message) {
            if ($message->payload == 'quit') {
                echo 'Aborting pubsub loop...', PHP_EOL;
                $pubsub->unsubscribe();
            } else {
                if ($message->kind == 'subscribe') {
                    echo 'subscribe...', PHP_EOL;
                }
                if ($message->kind == 'message') {
                    call_user_func_array($callback, [$message->payload, $message->channel]);
                }
            }
        }


    }

    /**
     * 消息发布
     * @param string $channel 频道
     * @param string $message 消息，必须是字符串
     * @return mixed
     */
    static function publish($channel, $message)
    {
        self::init();
        return self::$reids->publish($channel, $message);
    }

    /**
     * 向队列中添加一项数据
     * @param string $key 队列名称
     * @param string $data 数据，必须是字符串
     * @return mixed
     */
    static function addQueue($key, $data)
    {
        self::init();
        $key = md5('queue_' . $key);
        return self::$reids->rpush($key, $data);

    }

    /**
     * 从队列中取出一项，并执行回调函数
     * @param string $key
     * @param function $callback
     */
    static function getQueue($key, $callback)
    {
        self::init();
        $key = md5('queue_' . $key);
        while (1) {
            try {
                $data = self::$reids->blpop($key, 0);
                if ($data) {
                    if (isset($data[1])) {
                        call_user_func_array($callback, [$data[1]]);
                    } else {
                        call_user_func_array($callback, [$data]);
                    }
                }

            } catch (\Exception $e) {
                Log::error('*** QUEUE ***' . $e->getMessage());
            }
        }

    }

    /**
     * 加锁
     * @param $key 键
     * @param int $value 值
     * @param int $expires 时间
     * @return mixed
     */
    static function lock($key,$value=0,$expires=60){

        return self::init()->set($key,$value,'EX',$expires,'NX');
    }

    /**
     * 解锁
     * @param $key 键
     * @param int $value 值
     * @return bool|int
     */
    static function unlock($key,$value=0){

        $ret=self::init()->get($key);
        if($ret){
            if($ret!=$value){
                return false;
            }
            return self::init()->del($key);
        }

        return true;
    }
}
